package com.seed.bpmn.provider.activiti.common.util;

import com.seed.bpmn.engine.common.constants.BpmnConstants;
import com.seed.bpmn.engine.common.util.Empty;
import com.seed.bpmn.engine.dto.FlowDTO;
import com.seed.bpmn.engine.dto.NodeDTO;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmScope;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Activiti流程配置相关工具类
 * @author cscz89@126.com
 */
@Component
public class ActivitiUtil extends BpmnConstants {

	@Autowired
	private RuntimeService runtimeService;

	@Autowired
	private TaskService taskService;

	/**
	 * 获取多执行实例执行数量
	 * @param taskId 任务id
	 * @return
     */
	public Map<String,Integer> getMultiInstVars(String taskId){
		Map<String, Integer> nrVariables = new HashMap<String, Integer>();

		if(Empty.isNotEmpty(taskId)){
			//多实例要用到的变量名
			List<String> nrVariableNames = new ArrayList<String>();
			//多实例总数量
			nrVariableNames.add(ATTRIBUTE_MULTIINSTANCE_TOTAL);
			//多实例已完成数量
			nrVariableNames.add(ATTRIBUTE_MULTIINSTANCE_COMPLETED);

			Task task = this.taskService.createTaskQuery().taskId(taskId).singleResult();
			if(Empty.isNotEmpty(task)) {
				Map<String, Object> nrVars = runtimeService.getVariables(task.getExecutionId(), nrVariableNames);

				Object nrTotal = nrVars.get(ATTRIBUTE_MULTIINSTANCE_TOTAL);
				Object nrCompleted = nrVars.get(ATTRIBUTE_MULTIINSTANCE_COMPLETED);

				if(Empty.isNotEmpty(nrTotal) && Empty.isNotEmpty(nrCompleted)){
					nrVariables.put(ATTRIBUTE_MULTIINSTANCE_TOTAL,(Integer) nrTotal);
					nrVariables.put(ATTRIBUTE_MULTIINSTANCE_COMPLETED,(Integer) nrCompleted);
				}
			}
		}
		return nrVariables;
	}

	/**
	 * 判断当前任务是不是多实例环节中最后一个，true:是、false不是
	 * @param taskId 任务id
	 * @return
     */
	public boolean multiInstLast(String taskId){
		Map<String, Integer> nrVariables = this.getMultiInstVars(taskId);

		Integer nrTotal = nrVariables.get(ATTRIBUTE_MULTIINSTANCE_TOTAL);
		Integer nrCompleted = nrVariables.get(ATTRIBUTE_MULTIINSTANCE_COMPLETED);

		if(Empty.isNotEmpty(nrTotal) && Empty.isNotEmpty(nrCompleted)){
			//当前任务为多实例任务中的最后一个实例，
			return nrCompleted + 1 == nrTotal ;
		}else{
			return false;
		}
	}

	/**
	 * 递归获取下一节点数据
	 * @param taskId 任务id
	 * @param transitions 当前任务出去的流转线集合
	 * @param flows 下一流转线及目标任务节点配置集合
     * @param flow 需保留的上一个流转线
     */
	public void getNextTransitionsProperties(String taskId, List<PvmTransition> transitions, List<FlowDTO> flows, FlowDTO flow){
		for(PvmTransition t : transitions){
			FlowDTO dto = new FlowDTO();

			//流转线目标，有：网关、任务节点、子流程、结束事件等
			PvmActivity d = t.getDestination();

			//流转线目标类型
			String type = (String)d.getProperty(ATTRIBUTE_TYPE);

			//流转线ID
			String id = t.getId();

			//流转线名称
			String name = t.getProperty(ATTRIBUTE_NAME) + "";

			if(Empty.isNotEmpty(flow)){
				id = flow.getId();
				name = flow.getName();
			}
			flow = null;

			//封装流转线上的参数
			String fd = (String) t.getProperty(ELEMENT_DOCUMENTATION);
			if(Empty.isNotEmpty(fd)){
				JSONObject fed = JSONObject.fromObject(fd);
				if(fed.has(BpmnConstants.ATTRIBUTE_FLOW_BACK)){
					dto.setBack(fed.getBoolean(BpmnConstants.ATTRIBUTE_FLOW_BACK));
				}

				if(fed.has(BpmnConstants.ATTRIBUTE_CONTROL_CODE)){
					JSONArray controlCode = fed.getJSONArray(BpmnConstants.ATTRIBUTE_CONTROL_CODE);
					dto.setControlCode(DTOUtil.arrayToMap(controlCode));
				}
			}

			if(type.endsWith(ELEMENT_GATEWAY) || ELEMENT_TASK_SERVICE.equals(type)){

				//目标类型为网关或者serviceTask时，继续获取
				List<PvmTransition> tsList = d.getOutgoingTransitions();
				this.getNextTransitionsProperties(taskId, tsList, flows,flow);

			}else if(ELEMENT_SUBPROCESS.equals(type)){

				dto.setId(id);
				dto.setName(name);
				dto.setType(type);

				//下一环节为子流程时，获取子流程第一个任务节点参数进行封装
				PvmActivity sd = t.getDestination();
				List<? extends PvmActivity> list = sd.getActivities();
				for(PvmActivity a : list){
					//找到开始节点
					if(ELEMENT_EVENT_START.equals(a.getProperty(ATTRIBUTE_TYPE))){
						List<PvmTransition> outgoingTransitions = a.getOutgoingTransitions();
						if(!Empty.isEmpty(outgoingTransitions)){
							//获取开始节点后的第一个用户任务的属性
							PvmActivity destination = outgoingTransitions.get(0).getDestination();

							String seds = (String) destination.getProperty(ELEMENT_DOCUMENTATION);
							JSONObject sed = new JSONObject();
							if(Empty.isNotEmpty(seds)){
								sed = JSONObject.fromObject(seds);
							}

							//流程节点信息封装
							NodeDTO n = new NodeDTO();
							n.setId(destination.getId());
							n.setName(destination.getProperty(ATTRIBUTE_NAME).toString());
							//流程节点配置封装
							n = DTOUtil.getNodeDTO(sed,n);

							dto.setNode(n);
							break;
						}
					}
				}

				flows.add(dto);

			}else if(ELEMENT_EVENT_END.equals(type)){
				//-----目标类型为结束事件时----

				//获取结束事件父亲对象
				PvmScope parent = d.getParent();

				//父亲对象为非流程定义对象时
				if(parent instanceof PvmActivity){
					String parentType = (String)parent.getProperty(ATTRIBUTE_TYPE);

					//子流程中的结束节点
					if(ELEMENT_SUBPROCESS.equals(parentType)) {
						//多实例属性
						String multiInstance = (String) parent.getProperty(ATTRIBUTE_TASK_MULTIINSTANCE);

						if(Empty.isNotEmpty(multiInstance)){

							//判断当前任务是不是多实例环节中最后一个
							boolean islast = this.multiInstLast(taskId);

							//不是最后一个实例时，封装当前流转线
							if(!islast){
								flow = new FlowDTO();
								flow.setId(id);
								flow.setName(name);
							}

							//使用子流程对象，继续获取子流程目标对象相关配置信息
							PvmActivity parentActivity = (PvmActivity) parent;
							List<PvmTransition> tsList = parentActivity.getOutgoingTransitions();
							this.getNextTransitionsProperties(taskId, tsList, flows,flow);

							flow = null;
							continue;
						}
					}else{
						//非子流程
						PvmActivity parentActivity = (PvmActivity) parent;
						List<PvmTransition> tsList = parentActivity.getOutgoingTransitions();
						this.getNextTransitionsProperties(taskId, tsList, flows,flow);
						continue;
					}
				}else if(parent instanceof ProcessDefinitionEntity){
					dto.setId(id);
					dto.setName(name);
					dto.setType(type);

					NodeDTO n = new NodeDTO();
					n.setId(d.getId());

					dto.setNode(n);
					flows.add(dto);
				}
			}else{

				dto.setId(id);
				dto.setName(name);
				dto.setType(type);

				String nodeType = null;

				//获取流程节点documentation上配置的参数
				String dd = (String) d.getProperty(ELEMENT_DOCUMENTATION);
				JSONObject documentation = new JSONObject();
				if(Empty.isNotEmpty(dd)){
					documentation = JSONObject.fromObject(dd);
					//获取下一节点类型
					if(documentation.has(ATTRIBUTE_TYPE)){
						nodeType = documentation.getString(ATTRIBUTE_TYPE);
					}
				}

				//判断是否为开始节点出来的线
				boolean isStart = false;
				if(Empty.isNotEmpty(nodeType)){
					String stype = (String) t.getSource().getProperty(ATTRIBUTE_TYPE);
					isStart = ELEMENT_EVENT_START.equals(stype);
				}

				//下一节点为拟稿节点
				if(ATTRIBUTE_TASK_DRAFT.equals(nodeType) && isStart){
					List<PvmTransition> tsList = d.getOutgoingTransitions();
					this.getNextTransitionsProperties(taskId, tsList, flows,flow);
					continue;
				}else{
					NodeDTO n = new NodeDTO();
					n.setId(d.getId());
					n.setGroups(documentation.get(ATTRIBUTE_TASK_USER_CANDIDATEGROUPS)+"");

					//传阅任务节点时,添加节点名称
					if(ATTRIBUTE_TASK_CIRCULATION.equals(nodeType)){
						n.setName(d.getProperty(ATTRIBUTE_NAME).toString());
					}
					//流程节点配置封装
					n = DTOUtil.getNodeDTO(documentation,n);
					dto.setNode(n);
				}

				flows.add(dto);
			}
		}
	}
}
